#region Using

using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;
using System.Text.RegularExpressions;
using System.Net;
using System.IO;
using System.Globalization;
using System.Collections.ObjectModel;

#endregion

namespace SemanticEngine
{
	public static class DocumentFinder
	{

		public static Collection<SemanticDocument> Parse(Uri url)
		{
			string html = WebHelper.DownloadWebPage(url);
			return Parse(url, html);
		}

		public static Collection<SemanticDocument> Parse(Uri url, string html)
		{
			Collection<SemanticDocument> list = new Collection<SemanticDocument>();
			Collection<Uri> foafList = FindLinks(html, "foaf");
			AddDocumentsToList(url, list, DocumentType.Foaf, foafList);

			Collection<Uri> siocList = FindLinks(html, "sioc");
			AddDocumentsToList(url, list, DocumentType.Sioc, siocList);

			Collection<Uri> apmlList = FindLinks(html, "apml");
			AddDocumentsToList(url, list, DocumentType.Apml, apmlList);

			return list;
		}

		private const string PATTERN = "<head.*<link( [^>]*title=\"{0}\"[^>]*)>.*</head>";
		private static readonly Regex HREF = new Regex("href=\"([^\"]*)\"", RegexOptions.IgnoreCase | RegexOptions.Compiled);

		/// <summary>
		/// Finds semantic links in a given HTML document.
		/// </summary>
		/// <param name="type">The type of link. Could be foaf, apml or sioc.</param>
		/// <param name="html">The HTML to look through.</param>
		/// <returns></returns>
		public static Collection<Uri> FindLinks(string html, string type)
		{
			MatchCollection matches = Regex.Matches(html, string.Format(CultureInfo.InvariantCulture, PATTERN, type), RegexOptions.IgnoreCase | RegexOptions.Singleline);
			Collection<Uri> urls = new Collection<Uri>();

			foreach (Match match in matches)
			{
				if (match.Groups.Count == 2)
				{
					string link = match.Groups[1].Value;
					Match hrefMatch = HREF.Match(link);

					if (hrefMatch.Groups.Count == 2)
					{
						Uri url;
						string value = hrefMatch.Groups[1].Value;
						if (Uri.TryCreate(value, UriKind.RelativeOrAbsolute, out url))
						{
							urls.Add(url);
						}
					}
				}
			}

			return urls;
		}

		private static void AddDocumentsToList(Uri url, Collection<SemanticDocument> list, DocumentType type, Collection<Uri> urls)
		{
			foreach (Uri htmlUrl in urls)
			{
				Uri absoluteUrl = WebHelper.MakeAbsolute(htmlUrl, url);
				SemanticDocument doc = LoadDocument(type, absoluteUrl);
				if (doc != null)
				{
					list.Add(doc);
				}
			}
		}

		private static SemanticDocument LoadDocument(DocumentType type, Uri absoluteUrl)
		{
			try
			{
				//XmlDocument xml = new XmlDocument();
				//xml.Load(absoluteUrl.ToString());

				SemanticDocument doc = new SemanticDocument();
				//doc.Xml = xml;
				doc.DocumentType = type;
				doc.Url = absoluteUrl;
				return doc;
			}
			catch (XmlException)
			{
				return null;
			}
		}

	}
}
